package com.atguigu.exam.service.impl;


import com.atguigu.exam.entity.Category;
import com.atguigu.exam.entity.Question;
import com.atguigu.exam.mapper.CategoryMapper;
import com.atguigu.exam.mapper.QuestionMapper;
import com.atguigu.exam.service.CategoryService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.LongStream;


@Slf4j
@Service
public class CategoryServiceImpl implements CategoryService {

    @Autowired
    private CategoryMapper categoryMapper;
    @Autowired
    private QuestionMapper questionMapper;

    @Override
    public List<Category> getAllCategories() {
//        1.获取所有题目分类的基础信息，并按sort字段排序
        List<Category> categories = categoryMapper.selectList(new LambdaQueryWrapper<Category>().orderByAsc(Category::getSort));
//        2.为分类列表填充题目数量
        fillQuestionCount(categories);
        return categories;
    }

    @Override
    public List<Category> getCategoryTree() {
//        · 思路：需要将从数据库查出的扁平列表数据，在内存中高效地组装成树。
//        1.先获取所有分类，按sort排序
        List<Category> allCategories = categoryMapper.selectList(new LambdaQueryWrapper<Category>().orderByAsc(Category::getSort));
//        2.为每个分类填充其自身的题目数量，这里返回一个map
        fillQuestionCount(allCategories);
//        3.构建树形结构并返回
        List<Category> buildTree = buildTree(allCategories);
        log.info("查询类别的树状结构集合如下：{}",buildTree);
        return buildTree;
    }


    /**
     * 新增新的分类
     * @param category
     */
    @Override
    public void addCategory(Category category) {
        LambdaQueryWrapper<Category> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Category::getParentId,category.getParentId());
        lambdaQueryWrapper.eq(Category::getName,category.getName());
        Long count = categoryMapper.selectCount(lambdaQueryWrapper);
        if (count > 0){
            log.error("当前父类id下，该子分类名已经重复了，请取别的名称！",category.getParentId(),category.getName());
            throw new RuntimeException("当前父类id下，该子分类名已经重复了，请取别的名称！");

        }
        categoryMapper.insert(category);

    }

    @Override
    public void updateCategory(Category category) {
        categoryMapper.updateById(category);
    }

    @Override
    public void deleteCategory(Long id) {
//        1.检查是否为不允许删除的固定分类
        Category category = categoryMapper.selectById(id);
        if (category != null && category.getParentId() == 0){
            throw new RuntimeException("不允许删除固定的一级分类！");
        }
//        2.检查该分类下是否存在子类：
        Long childcount = categoryMapper.selectCount(new LambdaQueryWrapper<Category>().eq(Category::getParentId, id));
        if (childcount >0 ){
            throw new RuntimeException("该分类下有子类，无法删除！");
        }
//        3.检查该分类下是否存在题目：
        Long questionCount = questionMapper.selectCount(new LambdaQueryWrapper<Question>().eq(Question::getCategoryId, id));
        if (questionCount > 0){
            throw new RuntimeException("该分类下有题目，无法删除！");
        }
//        4.检查都结束后，执行删除：
        categoryMapper.deleteById(category);
    }

    /**
     * 私有辅助方法，用于构建树形结构
     */
    private List<Category> buildTree(List<Category> categories){
        //TODO
//        1.使用stream API按parentId进行分组，得到map<parentId,List<children>
        Map<Long, List<Category>> childrenMap = categories.stream().collect(Collectors.groupingBy(Category::getParentId));
//        2.遍历所有分类，为他们设置children属性，并递归累加题目数量
        categories.forEach(category -> {
//            从map中找到当前分类的所有子类
            List<Category> children = childrenMap.getOrDefault(category.getId(), new ArrayList<>());
            category.setChildren(children);

//            汇总子分类的题目数量，找到父分类
            Long childrenQuestionCount = children.stream().mapToLong(c -> c.getCount() != null ? c.getCount() : 0L).sum();
            Long selfQuestionCount = category.getCount() != null?category.getCount():0L;

//            父分类的总数 = 自身题目数 + 所有子分类题目总数之和
            category.setCount(selfQuestionCount+childrenQuestionCount);
        });
//        3.筛选出所有顶级分类（父id为0）作为树的根节点，按条件parentId == 0过滤分类，只留顶级分类
        return categories.stream()
                .filter(c->c.getParentId() == 0)
                .collect(Collectors.toList());
    }

    /**
     * 私有辅助方法，用于填充题目数
     */
    private void fillQuestionCount(List<Category> categories){
//        1.一次性查询出所有分类的题目数量，getCategoryQuestionCount方法获取某分类下题目的数量
        List<Map<Long,Object>> questionCountList = questionMapper.getCategoryQuestionCount();
//        2.将查询结果从List<Map>转换为Map<categoryId,count> 便于快速查找
        Map<Long,Long> questionCountMap = questionCountList.stream().collect(Collectors.toMap(
        //Collectors.toMap()是一个工具方法，用于把列表转换为Map。第一个 Lambda 表达式（map -> ...）定义
//      从列表元素中取什么作为 Map 的键; 第二个 Lambda 表达式：定义从列表元素中取什么作为对应的值
                map -> Long.valueOf(map.get("category_id").toString()), //取每个category_id转为Long类型，作为键
                map -> Long.valueOf(map.get("count").toString()) ////取每个count转为Long类型，作为值
        ));
//        3.遍历分类列表，为每个分类设置其对应的题目数量(属性）
        categories.forEach(category -> {
            category.setCount(questionCountMap.getOrDefault(category.getId(),0L));
            //遍历分类表的每个种类，为每个种类设置数量；
//            对questionCountMap使用getOrDefault方法，传入我们前端传来的分类列表的每个种类的id，返回我们上面
//            map给统计出的该分类id下的值，如果没有该分类，默认是0
        });
    }
}